/*
 *  BlipUpInterface.h
 *  BlipUp
 *
 *  Created by Pete Bunting on 11/01/2012.
 *  Copyright 2012 Pete Bunting.
 * 
 *  BlipUp is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  BlipUp is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with BlipUp.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#ifndef BlipUpInterface_H
#define BlipUpInterface_H

#include <iostream>

#include <QtGui>
#include <QtNetwork>
#include <QtCore>
#include <QtXML>
#include <QtGlobal>

#include "libexif/exif-data.h"

#include "BlipUpException.h"

using namespace std;

namespace blipup
{
    struct BlipDetails
    {
        QString label;
        QString filepath;
        QDateTime date;
        QString title;
        QString description;
        QString tags;
    };
    
    static const QString secertStr = "9342d4736be57431f377a89b2d03354a";
    static const QString apiStr = "dfb78d383c8293d8bbdd5d647789f1a5";
    
    inline QString getHTTReplyErrMessage(QNetworkReply::NetworkError code)
    {
        QString returnStr = "";
        if(code == QNetworkReply::ConnectionRefusedError)
        {
            returnStr = "The remote server refused the connection (the server is not accepting requests).";
        }
        else if(code == QNetworkReply::RemoteHostClosedError)
        {
            returnStr = "The remote server closed the connection prematurely, before the entire reply was received and processed.";
        }
        else if(code == QNetworkReply::HostNotFoundError)
        {
            returnStr = "The remote host name was not found (invalid hostname)";
        }
        else if(code == QNetworkReply::TimeoutError)
        {
            returnStr = "The connection to the remote server timed out";
        }
        else if(code == QNetworkReply::OperationCanceledError)
        {
            returnStr = "The operation was canceled via calls to abort() or close() before it was finished.";
        }
        else if(code == QNetworkReply::SslHandshakeFailedError)
        {
            returnStr = "The SSL/TLS handshake failed and the encrypted channel could not be established. The sslErrors() signal should have been emitted.";
        }
        else if(code == QNetworkReply::TemporaryNetworkFailureError)
        {
            returnStr = "The connection was broken due to disconnection from the network, however the system has initiated roaming to another access point. The request should be resubmitted and will be processed as soon as the connection is re-established.";
        }
        else if(code == QNetworkReply::ProxyConnectionRefusedError)
        {
            returnStr = "The connection to the proxy server was refused (the proxy server is not accepting requests)";
        }
        else if(code == QNetworkReply::ProxyConnectionClosedError)
        {
            returnStr = "The proxy server closed the connection prematurely, before the entire reply was received and processed";
        }
        else if(code == QNetworkReply::ProxyNotFoundError)
        {
            returnStr = "The proxy host name was not found (invalid proxy hostname)";
        }
        else if(code == QNetworkReply::ProxyTimeoutError)
        {
            returnStr = "The connection to the proxy timed out or the proxy did not reply in time to the request sent";
        }
        else if(code == QNetworkReply::ProxyAuthenticationRequiredError)
        {
            returnStr = "The proxy requires authentication in order to honour the request but did not accept any credentials offered (if any)";
        }
        else if(code == QNetworkReply::ContentAccessDenied)
        {
            returnStr = "The access to the remote content was denied (similar to HTTP error 401)";
        }
        else if(code == QNetworkReply::ContentOperationNotPermittedError)
        {
            returnStr = "The operation requested on the remote content is not permitted";
        }
        else if(code == QNetworkReply::ContentNotFoundError)
        {
            returnStr = "The remote content was not found at the server (similar to HTTP error 404)";
        }
        else if(code == QNetworkReply::AuthenticationRequiredError)
        {
            returnStr = "The remote server requires authentication to serve the content but the credentials provided were not accepted (if any)";
        }
        else if(code == QNetworkReply::ContentReSendError)
        {
            returnStr = "The request needed to be sent again, but this failed for example because the upload data could not be read a second time.";
        }
        else if(code == QNetworkReply::ProtocolUnknownError)
        {
            returnStr = "The Network Access API cannot honor the request because the protocol is not known";
        }
        else if(code == QNetworkReply::ProtocolInvalidOperationError)
        {
            returnStr = "The requested operation is invalid for this protocol";
        }
        else if(code == QNetworkReply::UnknownNetworkError)
        {
            returnStr = "An unknown network-related error was detected";
        }
        else if(code == QNetworkReply::UnknownProxyError)
        {
            returnStr = "An unknown proxy-related error was detected";
        }
        else if(code == QNetworkReply::UnknownContentError)
        {
            returnStr = "An unknown error related to the remote content was detected";
        }
        else if(code == QNetworkReply::ProtocolFailure)
        {
            returnStr = "A breakdown in protocol was detected (parsing error, invalid or unexpected responses, etc.)";
        }
        else
        {
            returnStr = "Unknown Error.";
        }
        
        return returnStr;
    };
    
    inline QString getBlipFotoErrMessage(unsigned int code)
    {
        QString replyStr = "";
        if(code == 1)
        {
            replyStr = "The API service is currently unavailable for a short period.";
        }
        else if(code == 10)
        {
            replyStr = "You have requested a resource that does not exist.";
        }
        else if(code == 11)
        {
            replyStr = "You have exceeded the set request limit for this time window.";
        }
        else if(code == 12)
        {
            replyStr = "The resource does not support the request method used.";
        }
        else if(code == 13)
        {
            replyStr = "The version number is invalid.";
        }
        else if(code == 14)
        {
            replyStr = "The resource is not available under this version of the API.";
        }
        else if(code == 50)
        {
            replyStr = "You have not supplied an API key with your request.";
        }
        else if(code == 51)
        {
            replyStr = "The supplied API key is not valid.";
        }
        else if(code == 52)
        {
            replyStr = "The supplied API key has been revoked.";
        }
        else if(code == 53)
        {
            replyStr = "The request was denied.";
        }
        else if(code == 54)
        {
            replyStr = "The supplied API key has expired.";
        }
        else if(code == 55)
        {
            replyStr = "The supplied API key has reached its IP address limit.";
        }
        else if(code == 56)
        {
            replyStr = "The supplied API Key is invalid for this domain.";
        }
        else if(code == 100)
        {
            replyStr = "The requested response format was not recognised.";
        }
        else if(code == 200)
        {
            replyStr = "You have not specified a search query.";
        }
        else if(code == 201)
        {
            replyStr = "You have not specified a journal entry date.";
        }
        else if(code == 202)
        {
            replyStr = "The specified journal entry date is not in yyyy-mm-dd format.";
        }
        else if(code == 203)
        {
            replyStr = "You must either specifiy an entry ID or both a username and enry date.";
        }
        else if(code == 204)
        {
            replyStr = "You cannot exceed 5 entries per lookup.";
        }
        else if(code == 206)
        {
            replyStr = "You must specifiy a valid entry ID.";
        }
        else if(code == 210)
        {
            replyStr = "You have not specified a view.";
        }
        else if(code == 211)
        {
            replyStr = "The specified view is not supported.";
        }
        else if(code == 212)
        {
            replyStr = "The specified max value is not a number.";
        }
        else if(code == 213)
        {
            replyStr = "The specified max value exceeds the allowed value of 48.";
        }
        else if(code == 220)
        {
            replyStr = "You have not specified any contributor names.";
        }
        else if(code == 221)
        {
            replyStr = "The user must be a member.";
        }
        else if(code == 222)
        {
            replyStr = "The entry is already favourited.";
        }
        else if(code == 223)
        {
            replyStr = "The limit of 3 favourites per 24 hours is already reached.";
        }
        else if(code == 224)
        {
            replyStr = "The user is already subscribed to the journal.";
        }
        else if(code == 225)
        {
            replyStr = "The user is not subscribed to the journal.";
        }
        else if(code == 226)
        {
            replyStr = "A user cannot subscribe to or unsubscribe from their own journal.";
        }
        else if(code == 227)
        {
            replyStr = "You cannot retrieve more than 5 contributors.";
        }
        else if(code == 500)
        {
            replyStr = "Deprecated - You have not specified an authentication token.";
        }
        else if(code == 501)
        {
            replyStr = "The specified authentication token is invalid.";
        }
        else if(code == 502)
        {
            replyStr = "You have not specified an authentication nonce.";
        }
        else if(code == 503)
        {
            replyStr = "You have not specified an authentication signature.";
        }
        else if(code == 504)
        {
            replyStr = "You have not specified an authentication token.";
        }
        else if(code == 505)
        {
            replyStr = "You have not specified an authentication timestamp.";
        }
        else if(code == 506)
        {
            replyStr = "The authentication window has elapsed.";
        }
        else if(code == 507)
        {
            replyStr = "The supplied authentication nonce has already been used.";
        }
        else if(code == 508)
        {
            replyStr = "Authentication failed.";
        }
        else if(code == 509)
        {
            replyStr = "The resource is not available with your API key.";
        }
        else if(code == 510)
        {
            replyStr = "No email address provided.";
        }
        else if(code == 511)
        {
            replyStr = "No password provided.";
        }
        else if(code == 512)
        {
            replyStr = "The requested entry does not exist.";
        }
        else if(code == 513)
        {
            replyStr = "The requested user does not exist.";
        }
        else if(code == 514)
        {
            replyStr = "No comment provided.";
        }
        else if(code == 515)
        {
            replyStr = "Comments are disabled for this entry.";
        }
        else if(code == 516)
        {
            replyStr = "No temporary token provided.";
        }
        else if(code == 517)
        {
            replyStr = "The temporary token was invalid.";
        }
        else if(code == 518)
        {
            replyStr = "You are unable to post a comment on this entry.";
        }
        else if(code == 519)
        {
            replyStr = "Comment could not be added.";
        }
        else if(code == 600)
        {
            replyStr = "Request did not include image data.";
        }
        else if(code == 601)
        {
            replyStr = "The image format is not supported, or the image did not upload successfully.";
        }
        else if(code == 602)
        {
            replyStr = "The image filesize exceeds the allowed limit.";
        }
        else if(code == 603)
        {
            replyStr = "The image dimensions are too small.";
        }
        else if(code == 604)
        {
            replyStr = "An internal error occured which prevented the file from uploading.";
        }
        else if(code == 605)
        {
            replyStr = "There is no previously uploaded image available.";
        }
        else if(code == 606)
        {
            replyStr = "Request did not include a date, or the image EXIF date was not set.";
        }
        else if(code == 607)
        {
            replyStr = "The entry date was invalid.";
        }
        else if(code == 608)
        {
            replyStr = "The entry date is a date in the future.";
        }
        else if(code == 609)
        {
            replyStr = "The entry date is before your signup date.";
        }
        else if(code == 610)
        {
            replyStr = "There is an existing journal entry for the entry date.";
        }
        else if(code == 611)
        {
            replyStr = "The entry date is before your date of birth.";
        }
        else if(code == 612)
        {
            replyStr = "The specified journal entry date does not correspond to a day of the year.";
        }
        else if(code == 613)
        {
            replyStr = "The image could not be reached from the specified URL.";
        }
        else if(code == 616)
        {
            replyStr = "The crop parameter was invalid.";
        }
        else if(code == 617)
        {
            replyStr = "The crop dimensions will not produce a valid image.";
        }
        else if(code == 1000)
        {
            replyStr = "An internal error occured and your request could not be processed.";
        }
        else
        {
            replyStr = "Unknown Error.";
        }
                
        return replyStr;
    }
    
    class BlipUpXMLParsing
    {
    public:
        BlipUpXMLParsing(){};
        bool parseAuthXML(QString blipXML, QString *username, QString *passToken) throw(BlipUpException);
        bool parseTimeXML(QString blipXML, QString *timeStamp) throw(BlipUpException);
        bool parseDateAvailableXML(QString blipXML, bool *available) throw(BlipUpException);
        bool parseBlipUploadXML(QString blipXML, QString *message) throw(BlipUpException);
        bool checkForError(QString blipXML) throw(BlipUpException);
        QString getErrorMessage(QString blipXML) throw(BlipUpException);
        unsigned int getErrorCode(QString blipXML) throw(BlipUpException);
        ~BlipUpXMLParsing(){};
    protected:
        QDomNode getData(QString blipXML) throw(BlipUpException);
    };
    
	class BlipUpInterface : public QMainWindow
	{	
		Q_OBJECT	
	public:
		BlipUpInterface();
		void addImage(QString file);
        void setAuthXML(QString xmlStr);
        void resizeEvent(QResizeEvent * event);
		~BlipUpInterface();
    private slots:	
		void addBlip();
        void removeBlip();
        void submitBlips();
        void saveBlips();
        void openBlips();
        void selectBlipInList(QListWidgetItem *item);
        void login();
        void logout();
    private:
        QString getTimeStamp()throw(BlipUpException);
        bool checkDateAvailable(QString dataStr);
        QListWidget *blipList;
        QWidget *centralWidget;
        QVBoxLayout *layoutOverall;
        QPlainTextEdit *descriptionTextEdit;
        QLineEdit *titleTextLine;
        QLineEdit *tagsTextLine;
        QLabel *imageView;
        QLabel *usernameLabel;
        QPushButton *loginButton;
        QPushButton *logoutButton;
        QHBoxLayout *hLayoutLogin;
        vector<BlipDetails*> *blips;
        BlipDetails *currentBlip;
        QImage *currentImage;
        QSettings *progSettings;
        bool authenticationSet;
        bool dateAvailableReply;
        bool timeStampReply;
        QString username;
        QString passToken;
	};
    
    class BlipUpAuthentic : public QDialog
	{
		Q_OBJECT
	public:
		BlipUpAuthentic(QWidget *parent, BlipUpInterface *mainInterface);
        ~BlipUpAuthentic();
    private slots:
        void goToAuthURL();
        void OKSlot();
        void replyAuthFinished(QNetworkReply *authReply);
    private:
        QLineEdit *codeTextLine;
        BlipUpInterface *mainInterface;
        
	};
    
    class BlipUpSubmittingDialog : public QDialog
	{
		Q_OBJECT
	public:
		BlipUpSubmittingDialog(QWidget *parent, vector<BlipDetails*> *blips, QString username, QString passToken);
        ~BlipUpSubmittingDialog();
    private slots:
        void closeSlot();
        void replyGetTimeStampFinished(QNetworkReply *reply);
        void replyDateAvailableFinished(QNetworkReply *reply);
        void replyBlipUploadedFinished();
        void blipUploadProgressSlot(qint64 bytesSent, qint64 bytesTotal);
        void blipUploadErrorSlot(QNetworkReply::NetworkError code);
    private:
        QPushButton *closeButton;
        QPlainTextEdit *feedbackText;
        QProgressBar *numOfBlipsProgress;
        QProgressBar *blipUploadProgress;
        vector<BlipDetails*> *blips;
        QString username;
        QString passToken;
        bool gettingTimeStampToCheckDataAvailable;
        bool gettingTimeStampToSubmitBlip;
        size_t currentBlipIdx;
        QNetworkReply *replyBlipUpload;
	};
}
#endif
